﻿using System;
using System.Collections.Generic;
using Framework;
using Framework.Resource;
using Game.Util;
using UnityEngine;
using XLua;

namespace Game.Lua.Base
{

    public class LuaManager : FrameworkComponent
    {
        internal  LuaEnv luaEnv = new LuaEnv(); //all lua behaviour shared one luaenv only!
        internal  float lastGCTime = 0;
        internal const float GCInterval = 1;//1 second 
        public  LuaEnv LuaEnv => luaEnv;
        
        private  LuaTable scriptEnv;

        private  ResourceManager m_resourceManager;

        private  Dictionary<string, byte[]> m_luaScriptMaps;

        private Action luaInit;
        private Action<float, float> luaUpdate;
        private void Start()
        {
            
            m_luaScriptMaps = new Dictionary<string, byte[]>();
            m_resourceManager = GameEntry.GetComponent<ResourceManager>();
            luaEnv.AddLoader(CustomLoader);


            AddBuildin();
            // LoadMainScripts();
        }



        void AddBuildin()
        {
            luaEnv.AddBuildin("lpeg",Game.LuaDLL.Lua.LoadLpeg);
            
            luaEnv.AddBuildin("sproto.core",Game.LuaDLL.Lua.LoadSprotoCore);
            
            luaEnv.AddBuildin("client.crypt",Game.LuaDLL.Lua.LoadClientCrypt);
        }
        
        public void Test()
        {
            string txt = m_resourceManager.LoadAssetSync<TextAsset>("Assets/Game/Scripts/Lua/Lua/network/client.lua.txt")?.text;
            if (txt!=null)
            {
                luaEnv.DoString(txt);
            }
        }
        public void LoadMainScripts()
        {
           // var table= CreatNewLuaScriptEnv();
           luaEnv.DoString("require 'main'");
           luaEnv.Global.Get("update",out luaUpdate);
           luaEnv.Global.Get("init",out luaInit);
           luaInit?.Invoke();
        }

        /// <summary>
        /// 清除缓存在内存中的lua脚本
        /// </summary>
        public  void ClearLuaScriptsCache()
        {
            m_luaScriptMaps.Clear();
        }
         byte[] CustomLoader(ref string filename)
        {
            if (m_luaScriptMaps.ContainsKey(filename))
            {
                return m_luaScriptMaps[filename];
            }
            else
            {
                string assetName = filename.Replace(".", "/");
                string luaAssetName = AssetUtility.GetLuaAssetPath(assetName);
                var script= m_resourceManager.LoadAssetSync<TextAsset>(luaAssetName);
                if (script == null)
                {
                    return null;
                }
                byte[] bytes=System.Text.Encoding.UTF8.GetBytes(script.text);
                m_resourceManager.UnloadAsset(luaAssetName,null);
                m_luaScriptMaps.Add(filename,bytes);
                return bytes;
            }
           
        } 
        public  LuaTable CreatNewLuaScriptEnv()
        {
            scriptEnv = luaEnv.NewTable();
            // 为每个脚本设置一个独立的环境，可一定程度上防止脚本间全局变量、函数冲突
            LuaTable meta = luaEnv.NewTable();
            meta.Set("__index", luaEnv.Global);
            scriptEnv.SetMetaTable(meta);
            meta.Dispose();
            return scriptEnv;
        }

        // public  void DoLuaByAssetName(string luaAssetName,string name, LuaTable luaEnvTable)
        // {
        //     luaEnv.DoString($"local type=require '{luaAssetName}' Obj=type.new()", name, luaEnvTable);
        // }
        public void DoString(string luaScript, string name, LuaTable envTable)
        {
            luaEnv.DoString(luaScript, name, envTable);
        }

        public  void Update()
        {
            if (Time.time - lastGCTime > GCInterval)
            {
                luaEnv.Tick();
                lastGCTime = Time.time;
            }
            
        }
        public override void OnUpdate(float elapseSeconds, float realElapseSeconds)
        {
            luaUpdate?.Invoke(elapseSeconds,realElapseSeconds);
        }

        public override void Shutdown()
        {
            luaUpdate = null;
            luaInit = null;
            // throw new System.NotImplementedException();
        }
    }

}